/*
 * Copyright (c) 2011 Srdjan VESIC.
 * Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; GNU Free Documentation License is available at
http://www.gnu.org/copyleft/fdl.html
*/ 
package map;

import java.awt.BasicStroke;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.StringTokenizer;

import core.Ville;
import core.vols.VolInstance;
import core.voyageur.Client;

import serveur.SimulationServeur;

/** 
 * 
 * Builds a map based on data extracted from a file
 * @author Buisson Jeandet Ramillien
 * @version 1.0
 */
@SuppressWarnings("serial")
public class PaintMap extends Canvas  {
	
	/** The set of airports. */
	private ArrayList<String> airportsList = new ArrayList<String>();
	private SimulationServeur serveur;
	
	private boolean displayFlights;
	private boolean displayLignes;
	private boolean displayClients;
	
	
	public PaintMap(SimulationServeur serveur) {
		this.serveur=serveur;
	}

	/** 
	 * Draws airports : circle for the position and name for each airport  
	 *  @param g Graphics containing the map
	 */
	public void paint(Graphics g) {
		Airport a;
		Airport voisin;
		Graphics2D g2d = (Graphics2D) g;
		Stroke drawingStroke = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{5}, 0);
		
		if(!serveur.getAeroports().isEmpty()) {
		// For each airport,
		java.util.Iterator<Airport> itrc = serveur.getAeroports().values().iterator();
		while(itrc.hasNext()) {
			a = itrc.next();
			// ... draw a circle...
			g.setColor(new Color(0,0,255));
			g.drawOval(a.getCoord().x, a.getCoord().y, 2, 2);
			// ... and write its code. 
			g.setColor(new Color(0,0,0));
			g.drawString(a.getCode(), a.getCoord().x, a.getCoord().y);
			
			if(!(a.getVoisins().isEmpty()) && displayLignes) {
				Stroke oldStroke = g2d.getStroke();
				g2d.setStroke(drawingStroke);
				Iterator<Airport> itra = a.getVoisins().iterator();
				while(itra.hasNext()) {
					voisin=itra.next();
						g.drawLine(a.getCoord().x, a.getCoord().y, voisin.getCoord().x, voisin.getCoord().y);
				}
				g2d.setStroke(oldStroke);
			}
		}
		
		//For each ville
		Iterator<Ville> itv = serveur.getVilles().values().iterator();
		while(itv.hasNext()) {
			Ville v = itv.next();
			// ... draw a circle...
			g.setColor(new Color(0,0,255));
			g.drawOval(v.getP().x, v.getP().y, 2, 2);
			// ... and write its code. 
			g.setColor(new Color(0,0,0));
			g.drawString(v.getNom(), v.getP().x, v.getP().y);
		}
			
		Iterator<VolInstance> itVols = serveur.getVolsEnCours().values().iterator();
		int i=0;
		boolean display=false;
		while(itVols.hasNext()) {
			VolInstance current = (VolInstance)itVols.next();
			display=false;
			if(displayClients) {			
				for(Client client : serveur.getClientsSuivis()) {
					if(current.getAvion().getPassagers().contains(client)) {
						display=true;
						break;
					}
				
				}
			}
				if(displayFlights || display) {
					Point pA = current.getDepart().getCoord();
					Point pB = current.getArrivee().getCoord();
					int xa = pA.x;
					int ya =pA.y;
					int xb = pB.x;
					int yb = pB.y;
					Point pM = new Point(pA);
					boolean aller = (current.getNumero()%10==1); 
					double pourcentage = 1-(current.getDistanceRestante()/(current.getDistance()));
					if (pourcentage>1) pourcentage = 1;
					pM.translate((int)((xb-xa)*pourcentage), (int)((yb-ya)*pourcentage));
					if (aller) {
						g.setColor(new Color(50,205,50));
						xa +=2;
						pM.x +=2;
					}
					else {
						g.setColor(new Color(246,29,5));
						xa -=2;
						pM.x -=2;
					}
					g.drawLine(xa, ya, pM.x, pM.y);
					
					g.setColor(new Color(0,0,0));
				}
			}		
		}
		g.drawRect(0, 0, 599, 599); 		// Border of the map.
	}
	
	
	
	
	/**
	 * @param displayClients the displayClients to set
	 */
	public void setDisplayClients(boolean displayClients) {
		this.displayClients = displayClients;
	}

	/** Repaints the canvas given a new set of airports. (The old ones are deleted.)
	 * @param a set of airports
	 * */
	public void updateCitiesAirportList(Hashtable<String, Airport> a) {
		serveur.setAeroports(a);
		serveur.majNeighbours(airportsList);
		serveur.createVolsFromAirports();
	}
		
	/** Updates the list of airports by reading them from filename (the old airports are deleted).
	 * 
	 * @param fileName name of the file from which airports data is extracted
	 */
	public void updateCitiesFromFile(String fileName) {
		// Create a new (empty) set of airports:
		serveur.clearAirports();
		airportsList.clear();

		try {
			// Read the file:
		    FileInputStream fstream = new FileInputStream(fileName);
		    // Get the object of DataInputStream
		    DataInputStream in = new DataInputStream(fstream);
	        BufferedReader br = new BufferedReader(new InputStreamReader(in));
		    String strLine;
		    String neighboursString; //Without coordinates
		    
		    //Read the file line by line:
		    strLine = br.readLine();
		    while (strLine != null)   {
	
		    	// If the line is empty, we hope that it is the end of the file and stop reading it.
		    	if (strLine.length() == 0) 
		    		break;
		    	
		    	
		    	
		    	// Tokenize the string.
			    StringTokenizer st = new StringTokenizer(strLine);
			    
			    // TODO: take into account possible errors. Here, we simply suppose that
			    // a string has an airport code, two integers and connections.
			    String code  = st.nextToken();
			    String x  = st.nextToken();
			    String y  = st.nextToken();
		
			    int cx = Integer.parseInt(x.trim());
		        int cy = Integer.parseInt(y.trim());
		        
		        neighboursString = code+" ";
		        try {
		        	while(true) neighboursString += st.nextToken()+ " ";
		        
		        } catch(Exception e) {
		        	
		        }
		        		        
		        airportsList.add(neighboursString);
		        
		        // We add the current airport to the list of airports. 
		        // TODO: add also the connections to an appropriate class or structure
		        // to be able to draw them later. 
		        Airport a  = new Airport(new Point(cx, cy), code);
		        serveur.addAeroport(a);
		       
		        // Read the next line. 
		        strLine = br.readLine();
		    }
		    
		    serveur.majNeighbours(airportsList);
		    serveur.createVolsFromAirports();

		    //Close the input stream
		    in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}

	public void setDisplayFlights(boolean displayFlights) {
		this.displayFlights = displayFlights;
	}

	public boolean isDisplayFlights() {
		return displayFlights;
	}

	/**
	 * @return the displayLignes
	 */
	public boolean isDisplayLignes() {
		return displayLignes;
	}

	/**
	 * @param displayLignes the displayLignes to set
	 */
	public void setDisplayLignes(boolean displayLignes) {
		this.displayLignes = displayLignes;
	}

	/**
	 * @return the displayClients
	 */
	public boolean isDisplayClients() {
		return displayClients;
	}

	/**
	 * @param serveur the serveur to set
	 */
	public void setServeur(SimulationServeur serveur) {
		this.serveur = serveur;
	}

	
	
	
}
